package com.cetc.operate.audit.aspect;

import com.cetc.operate.audit.annotation.OperateAudit;
import com.cetc.operate.audit.recorder.Recorder;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

import java.lang.reflect.Method;

@Aspect
public class OperateAuditAspect implements ApplicationContextAware {

    private ApplicationContext applicationContext;

    @Pointcut("@annotation(com.cetc.operate.audit.annotation.OperateAudit)")
    private void auditCut() {
    }

    @Around("auditCut()")
    public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        Throwable throwable = null;
        try {
            return proceedingJoinPoint.proceed();
        } catch (Throwable e) {
            throwable = e;
            throw throwable;
        } finally {
            this.doAudit(proceedingJoinPoint, throwable);
        }
    }

    private void doAudit(ProceedingJoinPoint proceedingJoinPoint, Throwable throwable) {
        MethodSignature methodSignature = (MethodSignature) proceedingJoinPoint.getSignature();
        Method method = methodSignature.getMethod();
        OperateAudit annotation = method.getAnnotation(OperateAudit.class);
        Class<?>[] parameterTypes = method.getParameterTypes();
        Object[] args = proceedingJoinPoint.getArgs();

        Recorder recorder = applicationContext.getBean(annotation.recorder());
        Object logBean = recorder.parseParameter(annotation, parameterTypes, args, throwable);
        recorder.save(logBean);
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}
